package com.atguigu.rabbitmq.springbootrabbitmq.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * @author gan
 * @create 2021-07-26 17:25
 */
@Slf4j
@Component //1
public class MyCallback implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback{

    @Resource  //2
    private RabbitTemplate rabbitTemplate;

    /*
    因为ConfirmCallback是RabbitTemplate的内部接口，而MyCallback不在
    RabbitTemplate内部，所以导致将来RabbitTemplate在调用自身接口到时候，
    调不到ConfirmCallback的实现类，得通过1、2、3三个步骤注入，并且顺序
    不能颠倒，不然就会报空指针异常。
     */
    @PostConstruct  //3
    public void init() {
        //注入
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);
    }

    /**
     *
     * 交换机确认回调方法
     * 1、发消息  交换机接收到了   回调
     *    1.1 correlationData 保存回调信息的ID以及相关信息
     *    1.2 交换机接收到消息 true
     *    1.3 cause null
     *
     * 2、发消息  交换机接收失败了  回调
     *    2.1 correlationData 保存回调消息的ID以及相关信息
     *    2.2 交换机收到消息  ack = false
     *    2.3 cause 失败的原因
     *
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        //
        String id = correlationData != null ? correlationData.getId() : "";
        if (ack){
//            System.out.println("交换机已经收到id为" + id + "的消息");
            log.info("交换机已经收到id为：{}的消息", id);
        }else {
//            System.out.println("交换机未收到id为" + id + "的消息，由于原因：" + cause);
            log.info("交换机未经收到id为：{}的消息", id);
        }
    }

    //可以在当消息传递过程中不可达目的地时将消息返回给生产者
    //只有不可达目的地的时候  才进行回退
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
//        System.out.println("消息：" + new String(message.getBody()) + "，被交换机是：" + exchange + " 退回，退回原因：" + replyText + "，路由Key是：" + routingKey);;
        log.error("消息：{}，被交换机：{}退回，退回原因：{}，路由key是：{}", new String(message.getBody()), exchange, replyText, routingKey);
    }
}
